#pragma once

#include<pthread.h>
#include<semaphore.h>
#include<queue>
#include<unistd.h>

template<class T>
class ring_queue
{
private:
    void P(sem_t& s)
    {
        sem_wait(&s);
    }

    void V(sem_t& s)
    {
        sem_post(&s);
    }

    void Lock(pthread_mutex_t& mutex)
    {
        pthread_mutex_lock(&mutex);
    }

    void UnLock(pthread_mutex_t& mutex)
    {
        pthread_mutex_unlock(&mutex);
    }

    static const int defaultnum = 10;
public:
    ring_queue(int num = defaultnum)
    :rq_(num),cpos(0),ppos(0)
    {
        sem_init(&csem_,0,0);
        sem_init(&psem_,0,10);
        pthread_mutex_init(&pmutex_,nullptr);
        pthread_mutex_init(&cmutex_,nullptr);
    }


    ~ring_queue()
    {
        sem_destroy(&csem_);
        sem_destroy(&psem_);
        pthread_mutex_destroy(&pmutex_);
        pthread_mutex_destroy(&cmutex_);
    }

    void push(const T& t)
    {
        P(psem_);
        Lock(pmutex_);
        rq_[ppos++] = t;
        UnLock(pmutex_);
        ppos %= rq_.size();
        V(csem_);
        sleep(1);
    }

    T pop()
    {
        P(csem_);
        Lock(cmutex_);
        T tmp = rq_[cpos++];
        UnLock(cmutex_);
        cpos %= rq_.size();
        V(psem_);

        return tmp;
    }



private:
    std::vector<T> rq_;
    sem_t csem_;
    sem_t psem_;
    pthread_mutex_t pmutex_;
    pthread_mutex_t cmutex_;
    int cpos;
    int ppos;
};